#include"Thread.hpp"
#include<vector>
#include<unistd.h>
#include<pthread.h> //POSIX线程库提供了互斥锁的实现

#define NUM 5

using namespace zzx;

int tickets = 1000; //共享资源,未加保护,可能会导致数据不一致、数据竞态条件

//定义互斥锁，保护共享资源
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//RAII风格的加锁和解锁,通过对象的生命周期管理资源的获取和释放
class LockGuard 
{
public:
    LockGuard(pthread_mutex_t* mutex)
        :_mutex(mutex)
    { 
        pthread_mutex_lock(_mutex); //对象构造时自动获取锁
    }

    ~LockGuard()
    {
        pthread_mutex_unlock(_mutex); //对象析构时自动释放锁
    }

    pthread_mutex_t* _mutex;
};

class ThreadData
{
public:
    ThreadData(const string& name, int& tickets, pthread_mutex_t& mutex)
        :_name(name),_tickets(tickets),_mutex(mutex),_total(0)
    { }

    ~ThreadData(){ }

    string _name;
    int& _tickets; //所有线程,最后都会引用(看到)同一个全局变量
    pthread_mutex_t& _mutex; ////所有线程,最后都会引用(看到)同一个全局锁
    int _total;
};

void route(ThreadData* td) //抢票系统
{
    while(true)
    {
        /*加锁粒度越细越好;
        加锁将对共享资源的访问从串行执行变为并行执行;
        竞争锁是自由竞争的,竞争锁能力强的线程会频繁获取锁,可能导致其他线程获取不到锁,造成其他线程饥饿*/
        
        LockGuard guard(&td->_mutex);  //方法2:RAII风格的加锁、解锁

        //pthread_mutex_lock(&td->_mutex);  //加锁
        if(td->_tickets > 0)
        {
            cout << td->_name << " running, get tickets: " << td->_tickets << endl;
            td->_tickets--;
            //pthread_mutex_unlock(&td->_mutex); //解锁
            td->_total++;
        }
        else
        {
            //pthread_mutex_unlock(&td->_mutex); //解锁
            break;
        }
    }
}

int main()
{
    vector<thread<ThreadData*>> threads; //
    vector<ThreadData*> datas;
    
    pthread_mutex_t mutex; //定义局部变量的锁
    pthread_mutex_init(&mutex, NULL); //初始化

    for(int i = 1; i <= NUM; i++)
    {    
        char* buffer = new char[64];
        snprintf(buffer, 128, "thread-%d", i);

        ThreadData* td = new ThreadData(buffer, tickets, mutex);
        threads.emplace_back(route, td, buffer); //
        datas.push_back(td);
    }
    
    for(auto& e : threads)
        e.start();

    for(auto& e : threads)
    {
        e.join();
        //cout << "wait thread done, thread is " << e.name() << endl;
        sleep(1);
    }

    for(auto& e : datas) //获取最终各个线程抢到得总票数
    {
        cout << e->_name << ": " << e->_total << endl;
    }

    pthread_mutex_destroy(&mutex);  //销毁
    
    return 0;
}
